package com.bstek.service.impl;

import com.bstek.entity.ItemEntity;
import com.bstek.enums.ItemTypeEnum;
import com.bstek.enums.QsAnalyzeType;
import com.bstek.service.ItemValidate;
import com.bstek.urule.RuleException;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @Description:
 * @Author: zhoulitong
 * @Date: 2021/4/9 13:57
 */
@Component("itemValidate")
public class ItemValidateImpl implements ItemValidate {
    /**
     * 括号答题区
     */
    private static final String PARENTHESES = "$(\\qquad)$";
    /**
     * 带数字的答题区
     */
    private static final String UNDER_LINE_REGEX = "<wn>\\d+</wn>";
    /**
     * 答题区nn
     */
    private static final String NN = "<nn[a-zA-z0-9\"'=\\s]*>.*?<\\/nn>";
    /**
     * 八个小短线答题区
     */
    private static final String SHORT_UNDER_LINE = "(_{8,})+";
    /**
     * 选项前缀
     */
    private static final String CHOICE_REGEX = "^[A-Z](\\. |．)";
    /**
     * 空格
     */
    private static final String SPACE = "&nbsp;";
    /**
     * 26个英文字母
     */
    public static final int LETTER_COUNT = 26;

    /**
     * 最小选项个数
     */
    public static final int OPTION_MIX_COUNT = 2;
    /**
     * 答案个数：两个
     */
    public static final int ANSWER_COUNT_2 = 2;
    /**
     * 换行符
     */
    private static final String BR = "<br>";


    private static final Map<String, String> ITEM_TYPE_MAPPING = new HashMap<>();
    private static final List<Integer> SUBTYPES_CHOICE = new ArrayList<>();
    private static final List<Integer> SUBTYPES_BLANK = new ArrayList<>();
    private static final List<Integer> SUBTYPES_LINE = new ArrayList<>();
    private static final List<Integer> SUBTYPES_SINGLE_CHOICE = new ArrayList<>();
    private static final List<Integer> SUBTYPES_DOUBLE_CHOICE = new ArrayList<>();
    private static final List<Integer> SUBTYPES_MULTI_CHOICE = new ArrayList<>();
    private static final List<Integer> SUBTYPES_JUDGE = new ArrayList<>();


    /**
     * 解析内容为空
     *
     * @param qsAnalyzeList
     */
    @Override
    public void analyzeIsEmpty(List<ItemEntity.QsAnalyze> qsAnalyzeList) {
        if (null == qsAnalyzeList || qsAnalyzeList.size() <= 0) {
            throw new RuleException("如果要显示解析，解析不能为空");
        }
        for (ItemEntity.QsAnalyze qsAnalyze : qsAnalyzeList) {
            for (String text : qsAnalyze.getTexts()) {
                if (StringUtils.isEmpty(text)) {
                    throw new RuleException("如果要显示解析，解析不能为空");
                }
            }
        }
    }

    @Override
    public void optsLengthCheck(List<String> opts) {
        if (!org.springframework.util.CollectionUtils.isEmpty(opts)) {
            for (String opt : opts) {
                if (opt != null && opt.length() > 5) {
                    throw new RuleException("选项长度太长");
                }
            }
        }
    }

    @Override
    public void checkEduAndType(Integer edu, Integer type) {
        setItemType();
        boolean result = ITEM_TYPE_MAPPING.containsKey(edu + "-" + type) || ITEM_TYPE_MAPPING.containsKey("0-" + type);
        if (!result) {
            throw new RuleException("题型学段与题目学段不符");
        }
    }

    @Override
    public void countWx(String stem, List<ItemEntity.Qs> qsList) {
        int count = getCount(stem, UNDER_LINE_REGEX);
        checkCount(count, qsList);
    }

    @Override
    public void countQxw(String stem, List<ItemEntity.Qs> qsList) {
        //匹配编辑器下划线的个数
        int count1 = getCount(stem, NN);
        //匹配带数字下划线的个数
        int count2 = getCount(stem, UNDER_LINE_REGEX);
        int countSum = count1 + count2;
        checkCount(countSum, qsList);
    }

    @Override
    public void countTllj(String stem, List<ItemEntity.Qs> qsList) {
        //校验填空题的空格
        //匹配编辑器下划线的个数
        int count1 = getCount(stem, NN);
        //匹配带数字下划线的个数
        int count2 = getCount(stem, UNDER_LINE_REGEX);
        //匹配8个_短下划线的个数
        int count3 = getCount(stem, SHORT_UNDER_LINE);
        int countSum = count1 + count2 + count3;
        checkCount(countSum, qsList);
    }

    @Override
    public void countQxwCount(List<ItemEntity.MainOption> mainOptions) {
        //选项个数不能低于2个
        if (mainOptions.size() < OPTION_MIX_COUNT) {
            throw new RuleException("选项个数不能低于两个");
        }
        //选项个数不能超过26
        if (mainOptions.size() > LETTER_COUNT) {
            throw new RuleException("选项个数最多26个");
        }
    }

    @Override
    public void countQxwContent(List<ItemEntity.MainOption> mainOptions) {
        for (ItemEntity.MainOption mainOption : mainOptions) {
            if (null == mainOption) {
                throw new RuleException("选项不能为空");
            }
            if (org.apache.commons.lang.StringUtils.isBlank(mainOption.getText())) {
                throw new RuleException("选项不能为空");
            }
            if (StringUtils.isEmpty(mainOption.getText().replaceFirst("^[A-Z](\\. |．)", "").replace("<br>", "").trim())) {
                throw new RuleException("选项不能为空");
            }
        }
    }

    @Override
    public void countQxwOrder(List<ItemEntity.MainOption> mainOptions) {
        List<String> opts = new ArrayList<>();
        for (ItemEntity.MainOption mainOption : mainOptions) {
            opts.add(mainOption.getText());
        }
        checkOrderOpts(opts);
    }


    @Override
    public void mustAnswer(Integer subtype, String desc) {
        setItemSubType();
        // 不能没有答题区
        if (SUBTYPES_CHOICE.contains(subtype)) {
            if (getCount(desc, NN) == 0 && !org.apache.commons.lang.StringUtils.contains(desc, PARENTHESES)) {
                throw new RuleException("答题区不能为空");
            }
        }
    }

    @Override
    public void countYftkAnswer(Integer type, String desc, List<ItemEntity.QsAnswer> answers) {
        // 语法填空
        if (ItemTypeEnum.TYPE_5016.getType().equals(type)
                || ItemTypeEnum.TYPE_5407.getType().equals(type)) {
            //匹配编辑器下划线的个数
            int count1 = getCount(desc, NN);
            //匹配带数字下划线的个数
            int count2 = getCount(desc, UNDER_LINE_REGEX);
            int countSum = count1 + count2;
            checkAnswerCount(countSum, answers);
        }

    }

    @Override
    public void countSomeAnswer(Integer subtype, String desc, List<ItemEntity.QsAnswer> answers) {
        setItemSubType();
        if (SUBTYPES_BLANK.contains(subtype)) {
            //校验填空题的空格
            //匹配编辑器下划线的个数
            int count1 = getCount(desc, NN);
            //匹配带数字下划线的个数
            int count2 = getCount(desc, UNDER_LINE_REGEX);
            //匹配8个_短下划线的个数
            int count3 = getCount(desc, SHORT_UNDER_LINE);
            int blankCount = count1 + count2 + count3;
            checkAnswerCount(blankCount, answers);
        }
    }

    @Override
    public void countOpts(List<String> opts, Integer subtype) {
        if (SUBTYPES_CHOICE.contains(subtype)) {
            if (CollectionUtils.isEmpty(opts)) {
                throw new RuleException("最少需要包含一个选项");
            }
            //选项个数不能低于2个
            if (opts.size() < OPTION_MIX_COUNT) {
                throw new RuleException("选项个数不能低于两个");
            }
            //选项个数不能超过26
            if (opts.size() > LETTER_COUNT) {
                throw new RuleException("选项个数最多26个");
            }
        }
    }

    @Override
    public void contentOpts(List<String> opts, Integer subtype) {
        if (SUBTYPES_CHOICE.contains(subtype)) {
            for (int i = 0; i < opts.size(); i++) {
                String s = opts.get(i);
                if (StringUtils.isEmpty(s) ||
                        StringUtils.isEmpty(s.replaceFirst("^[A-Z](\\. |．)", "").trim()) ||
                        StringUtils.isEmpty(s.replaceFirst("^[A-Z](\\. |．)", "").replace(BR, "").trim())) {
                    throw new RuleException("选项不能为空");
                }
                if (getCount(s, CHOICE_REGEX) != 1) {
                    throw new RuleException("选项不规范,缺少选项前缀");
                }
            }
        }
    }

    @Override
    public void orderOpts(List<String> opts, Integer subtype) {
        if (SUBTYPES_CHOICE.contains(subtype)) {
            checkOrderOpts(opts);
        }
    }

    @Override
    public void lineOpts(List<ItemEntity.LineOption> lineOptions, Integer subtype) {
        if (SUBTYPES_LINE.contains(subtype)) {
            // 连线题的矩阵第二列相当于选项
            List<String> opts = lineOptions.get(1).getTexts();
            countOpts(opts, subtype);
            contentOpts(opts, subtype);
            orderOpts(opts, subtype);
        }
    }

    @Override
    public void countAnswer(List<ItemEntity.QsAnswer> qsAnswers, Integer subtype, Integer type) {
        for (ItemEntity.QsAnswer ans : qsAnswers) {
            String ansTextStr = ans.getTexts().get(0);
            if (SUBTYPES_SINGLE_CHOICE.contains(subtype) || SUBTYPES_LINE.contains(subtype)
                    || ItemTypeEnum.TYPE_5011.getType().equals(type)
                    || ItemTypeEnum.TYPE_5029.getType().equals(type)) {
                if (org.apache.commons.lang.StringUtils.isNotEmpty(ansTextStr) && 1 != ansTextStr.length()) {
                    throw new RuleException("单项选择答案只能有一个");
                }
            }

            if (SUBTYPES_DOUBLE_CHOICE.contains(subtype)) {
                if (org.apache.commons.lang.StringUtils.isNotEmpty(ansTextStr) && ansTextStr.length() != ANSWER_COUNT_2) {
                    throw new RuleException("双项选择答案只能有两个");
                }
            }
            if (SUBTYPES_MULTI_CHOICE.contains(subtype)) {
                if (org.apache.commons.lang.StringUtils.isNotEmpty(ansTextStr) && ansTextStr.length() < ANSWER_COUNT_2) {
                    throw new RuleException("多项选择答案至少有两个");
                }
            }
        }

    }

    @Override
    public void typeAnswer(List<ItemEntity.QsAnswer> qsAnswers, Integer subtype) {
        for (ItemEntity.QsAnswer ans : qsAnswers) {
            if (SUBTYPES_JUDGE.contains(subtype)) {
                //判断题答案格式
                for (String text : ans.getTexts()) {
                    List<String> list = Arrays.asList("Y", "N");
                    if (!list.contains(text)) {
                        throw new RuleException("判断题答案错误");
                    }
                }
            }
        }
    }

    //todo:第三层list里的复杂循环。。。。。。。。
    @Override
    public void contentAnswer(List<ItemEntity.QsAnswer> qsAnswers, List<String> opts,
                              List<ItemEntity.LineOption> lineOptions, List<ItemEntity.MainOption> mainOptions,
                              Integer type, Integer subtype,Boolean answerObjective) {
        for (int i1 = 0; i1 < qsAnswers.size(); i1++) {
            int ansCount = i1 + 1;
            ItemEntity.QsAnswer qsAnswer = qsAnswers.get(i1);
            int answerCount = 0;
            if (CollectionUtils.isEmpty(qsAnswer.getTexts())) {
                answerCount = 1;
            } else {
                answerCount = qsAnswer.getTexts().stream().filter(s -> (StringUtils.isEmpty(s.replace(SPACE, "").trim()) || null == s)).collect(Collectors.toList()).size();
            }
            if (answerCount > 0) {
                //答案或者备选答案内容为空
                if (qsAnswers.size() == 1) {
                    throw new RuleException("答案内容不能为空");
                } else {
                    throw new RuleException("答案内容不能为空");
                }

            }
        }

        //校验客观型答案不能为图片、音频
        if (SUBTYPES_BLANK.contains(subtype)) {
            if (answerObjective) {
                for (ItemEntity.QsAnswer answer : qsAnswers) {
                    for (String text : answer.getTexts()) {
                        if (parseIsHasTag(text, "img")) {
                            throw new RuleException("客观型答案不能含有图片");
                        }

                    }
                }
            }
        }

        if (SUBTYPES_LINE.contains(subtype)) {
            //校验连线数量、答案数量
            if (lineOptions.size() >= OPTION_MIX_COUNT) {
                if (lineOptions.get(0).getTexts().size() == qsAnswers.size()) {
                    for (ItemEntity.LineOption lineOption : lineOptions) {
                        if (lineOption.getTexts().size() < 2) {
                            throw new RuleException("连线题每组连线至少为两个");
                        }
                    }
                } else {
                    throw new RuleException("连线题答案数量与左侧一列连线数量不符");
                }
            } else {
                throw new RuleException("连线题数量至少为两列");
            }
        }

        // 答案是否在选项中
        if (SUBTYPES_LINE.contains(subtype)) {
            opts = lineOptions.get(1).getTexts();
        }
        if (ItemTypeEnum.TYPE_5011.getType().equals(type)
                || ItemTypeEnum.TYPE_5029.getType().equals(type)) {
            opts = mainOptions.stream().map(a -> a.getText()).collect(Collectors.toList());
        }
        if (SUBTYPES_CHOICE.contains(subtype) || SUBTYPES_LINE.contains(subtype)
                || ItemTypeEnum.TYPE_5011.getType().equals(type)
                || ItemTypeEnum.TYPE_5029.getType().equals(type)) {
            // 答案是否在选项中
            for (ItemEntity.QsAnswer answer : qsAnswers) {
                for (String ans : answer.getTexts()) {
                    if (!checkOptionsAnswersIn(ans, opts)) {
                        throw new RuleException("答案未在选项中");
                    }
                }
            }
        }


    }

    @Override
    public void checkQsAnalyze(List<ItemEntity.QsAnalyze> analyzes , List<String> opts,
                               List<ItemEntity.QsAnswer> qsAnswers, Integer type, Integer subtype) {
        for (ItemEntity.QsAnalyze analyze : analyzes) {
            if (QsAnalyzeType.PARTITION.getCode() == analyze.getType()) {
                if(SUBTYPES_CHOICE.contains(subtype)
                        || ItemTypeEnum.TYPE_5011.getType().equals(type)
                        || ItemTypeEnum.TYPE_5029.getType().equals(type)) {
                    if (analyze.getTexts().size() != opts.size()) {
                        throw new RuleException("选择类题目分步解析数量与选项数量不符");
                    }
                }
                if(SUBTYPES_LINE.contains(subtype)){
                    throw new RuleException("连线题不支持分步解析");
                }
                if(SUBTYPES_BLANK.contains(subtype)) {
                    if (analyze.getTexts().size() != qsAnswers.size()) {
                        throw new RuleException("答题区个数与分空解析的空的个数不一致");
                    }
                }
            } else if (QsAnalyzeType.WHOLE.getCode() == analyze.getType()) {
                if(SUBTYPES_CHOICE.contains(subtype)
                        || ItemTypeEnum.TYPE_5011.getType().equals(type)
                        || ItemTypeEnum.TYPE_5029.getType().equals(type)
                        || SUBTYPES_LINE.contains(subtype)
                        || SUBTYPES_BLANK.contains(subtype)) {
                    if (analyze.getTexts().size() != 1) {
                        throw new RuleException("选择类题目整体解析数量只能为一个");
                    }
                }
            }
        }
    }

    /**
     * 检查答案是否在选项中
     * @param ans
     * @param options
     * @return
     */
    private boolean checkOptionsAnswersIn(String ans, List<String> options) {
        boolean isOut = true;
        ans = ans.trim();
        for (int j = 0; j < ans.length(); j++) {
            String an = ans.charAt(j) + "";
            boolean isIn = false;
            for (int i = 0; i < options.size(); i++) {
                String option = options.get(i);
                if (an.equals(option.substring(0, 1))) {
                    isIn = true;
                    break;
                }
            }
            if (!isIn) {
                isOut = false;
            }
        }
        return isOut;
    }


    /**
     * 内容中是否有标签名称
     * eg:parseTag(content,"img");
     *
     * @param content
     * @param tag
     * @return
     */
    public static boolean parseIsHasTag(String content, String tag) {
//        Document doc = Jsoup.parse(content);
//        Elements elemennts = doc.body().getAllElements();
//        for (Element elemennt : elemennts) {
//            if (elemennt.tag().getName().equals(tag)) {
//                return true;
//            }
//        }
        return false;
    }

    /**
     * 校验选项顺序是否正确
     *
     * @param opts
     * @return
     */
    private void checkOrderOpts(List<String> opts) {
        boolean check = true;
        char start = 'A';
        for (int i = 0; i < opts.size(); i++) {
            String option = opts.get(i);
            char a = option.charAt(0);
            if (a != start + i) {
                check = false;
            }
        }
        if (!check) {
            throw new RuleException("选项顺序错误");
        }
    }

    /**
     * 检验小题答题区和答案数量
     *
     * @param count
     * @param answers
     */
    private void checkAnswerCount(Integer count, List<ItemEntity.QsAnswer> answers) {
        if (count == 0) {
            throw new RuleException("答题区不能为空");
        }
        //检测题干中Blank的数量，答案和空的数量要相等
        if (answers.size() != (count)) {
            throw new RuleException("填空题空数量与答案数量不符");
        }
    }


    /**
     * 检验答题区和小题数量
     *
     * @param count
     * @param qsList
     */
    private void checkCount(Integer count, List<ItemEntity.Qs> qsList) {
        if (count == 0) {
            throw new RuleException("答题区不能为空");
        }
        if (qsList.size() != count) {
            throw new RuleException("答题区个数与小题数量不一致");
        }
    }


    /**
     * 指定正则，匹配命中次数
     *
     * @param stem
     * @param regex
     * @return
     */
    private int getCount(String stem, String regex) {
        int count = 0;
        if (org.apache.commons.lang.StringUtils.isBlank(stem)) {
            return 0;
        }
        Pattern matches = Pattern.compile(regex);
        Matcher m = matches.matcher(stem);
        while (m.find()) {
            count++;
        }
        return count;
    }

    /**
     * 放一些大题题型数据
     */
    private void setItemType() {
        ITEM_TYPE_MAPPING.put("3-1001", "");
        ITEM_TYPE_MAPPING.put("3-4001", "");
        ITEM_TYPE_MAPPING.put("3-5404", "");
        ITEM_TYPE_MAPPING.put("3-5005", "");
        ITEM_TYPE_MAPPING.put("3-5008", "");
        ITEM_TYPE_MAPPING.put("3-5003", "");
    }

    /**
     * 放一些小题题型数据
     */
    private void setItemSubType() {
        SUBTYPES_CHOICE.add(10011);
        SUBTYPES_BLANK.add(10011);
        SUBTYPES_BLANK.add(50011);
        SUBTYPES_LINE.add(50019);
        SUBTYPES_SINGLE_CHOICE.add(10011);
        SUBTYPES_DOUBLE_CHOICE.add(10011);
        SUBTYPES_MULTI_CHOICE.add(10011);
        SUBTYPES_JUDGE.add(10011);
    }
}
